<template>
  <div class="pro-tinymce-container" :class="{ border, radius }">
    <div class="pro-alert" v-if="showInfo">
      <pro-editor-info :proAlertInfo="[imageConf, attachmentConf]" />
    </div>
    <editor
      v-if="!flag"
      :id="editorId"
      :init="tinymceOpt"
      v-model="valueHtml"
      :disabled="disabled"
    />
  </div>
</template>
<script lang="ts" setup name="ProTinymce">
  import tinymce from 'tinymce'
  import Editor from '@tinymce/tinymce-vue'
  import 'tinymce/icons/default/icons.min.js'
  import 'tinymce/themes/silver'

  import {
    imageConfig,
    editorConfig,
    attachmentConfig,
    lightCss,
    darkCss
  } from './defaultConfig'
  import { FileConfType } from './configType'

  import usePlugin from './hooks/usePlugin'
  import useToolbar from './hooks/useToolbar'

  import { uuid } from '@/utils/uuid'
  import { useTheme } from '@/store/modules/theme'
  import { darkMode } from '~/types/theme'
  const theme = useTheme()

  interface tinymcePropsType {
    plugins?: Array<string> | ((defaultPlugins: Array<string>) => Array<string>)
    toolbar?: Array<string> | ((defaultToolbar: Array<string>) => Array<string>)
    height?: number
    minHeight?: number
    maxHeight?: number
    // 内容
    modelValue?: string
    // 只读
    disabled?: boolean
    // 富文本边框弧度：方形|圆形
    radius?: boolean
    //是否添加边框
    border?: boolean
    // 显示提示信息
    showInfo?: boolean
    // 编辑器配置
    editorConfig?: Record<string, unknown>
    // 上传图片配置
    imageConfig?: Partial<FileConfType>
    // 上传附件配置
    attachmentConfig?: Partial<FileConfType>
    // 默认字体
    defaultFont?: {
      fontSize: string
      fontName: string
    }
  }

  const props = withDefaults(defineProps<tinymcePropsType>(), {
    height: 400,
    modelValue: '',
    disabled: false,
    openPreview: true,
    radius: true,
    border: true,
    showInfo: true,
    editorConfig: () => editorConfig,
    imageConfig: () => imageConfig,
    attachmentConfig: () => attachmentConfig
  })

  // 基本配置合并
  const editorConf = computed(() => {
    const min_height = props.minHeight || props.height
    const max_height = props.maxHeight || props.height
    const css = theme.darkMode === darkMode.LIGHT ? lightCss : darkCss
    return {
      ...css,
      ...editorConfig,
      ...props.editorConfig,
      min_height,
      max_height
    }
  })

  // 图片上传配置合并
  const imageConf = computed(() => {
    return { ...imageConfig, ...props.imageConfig }
  })

  // 附件上传配置合并
  const attachmentConf = computed(() => {
    return { ...attachmentConfig, ...props.attachmentConfig }
  })

  // plugins、toolbar合并
  const defaultPlugins = usePlugin()
  const defaultToolbar = useToolbar()

  const plugins = computed(() => {
    const propPlugins = props.plugins
    let relPlugins = defaultPlugins
    if (typeof propPlugins === 'function') {
      relPlugins = propPlugins(defaultPlugins)
    } else if (Array.isArray(propPlugins)) {
      relPlugins = propPlugins
    }
    return relPlugins.join(' ')
  })

  const toolbar = computed(() => {
    const propToolbar = props.toolbar
    let relToolbar = defaultToolbar
    if (typeof propToolbar === 'function') {
      relToolbar = propToolbar(defaultToolbar)
    } else if (Array.isArray(propToolbar)) {
      relToolbar = propToolbar
    }
    return relToolbar.join(' ')
  })

  // 全部配置合并
  const tinymceOpt = {
    plugins: plugins.value,
    toolbar: toolbar.value,
    ...editorConf.value,
    setup: function (editor) {
      editor.on('init', function (ed) {
        if (props.defaultFont) {
          Object.keys(props.defaultFont).forEach((attrName) => {
            ed.target.editorCommands.execCommand(
              attrName,
              false,
              props.defaultFont![attrName]
            )
          })
        }
      })
    },
    images_upload_handler: (blobInfo, succFun, failFun) => {
      const file = blobInfo.blob()
      imageConf.value.uploadHandler(file, succFun, failFun, imageConf.value)
    },

    attachment_upload_handler: (file, succFun, failFun) => {
      attachmentConf.value.uploadHandler(
        file,
        succFun,
        failFun,
        attachmentConf.value
      )
    }
  }

  const valueHtml = ref<string>(props.modelValue)
  // 更新v-model值
  const emits = defineEmits(['update:modelValue'])

  watch(valueHtml, (val) => {
    emits('update:modelValue', val)
  })

  // 切换主题
  const flag = ref(false)
  const editorId = ref(uuid())
  watch(
    () => theme.darkMode,
    (val) => {
      const instance = tinymce.get(editorId.value)
      instance?.destroy()
      const css = val === darkMode.LIGHT ? lightCss : darkCss
      Object.assign(tinymceOpt, { ...css })
      flag.value = true
      nextTick(() => {
        flag.value = false
      })
    }
  )
</script>
<style lang="less" scoped>
  [data-theme='dark'] {
    .pro-tinymce-container {
      &.border {
        :deep(.tox-tinymce) {
          border: 1px solid #2a3746 !important;
        }
      }
    }
  }
  .pro-tinymce-container {
    .pro-alert {
      margin: 10px 0;
    }
    :deep(.tox-tinymce) {
      border: unset !important;
      border-radius: unset !important;
      .tox-statusbar__branding {
        display: none;
      }

      .tox-tbtn--bespoke {
        background: unset !important;
        &:hover {
          background: #cce2fa !important;
        }
      }
    }
    &.border {
      :deep(.tox-tinymce) {
        border: 1px solid #efeff5 !important;
      }
    }

    &.radius {
      :deep(.tox-tinymce) {
        border-radius: 6px !important;
      }
    }
  }
</style>
